//
//  MJRefresh+Extension.swift
//  Library_y
//
//  Created by JC on 2023/6/6.
//

import Foundation
import MJRefresh
import ObjectMapper

// MARK: UIScrollView - 扩展
public typealias HeaderRefreshBlock = (_ startPos: Int, _ reqCount: Int) -> Void
extension UIScrollView {
    
    // 扩展 - 属性
    private struct AssociatedKey {
        static var catchErrMsg: String = ""
        static var startPos: Int = 1
        static var reqCount: Int = 20
        static var noMore: Bool = false
        static var headerRefreshing: Bool = false
        static var hasFooter: Bool = false
        static var notLoaded: Bool = true
    }
    
    // 捕获到错误信息
    var catchErrMsg: String {
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.catchErrMsg) as? String ?? ""
        }
        set {
            objc_setAssociatedObject(self,
                                     &AssociatedKey.catchErrMsg,
                                     newValue,
                                     .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    // 起始位置
    var startPos: Int {
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.startPos) as? Int ?? 1
        }
        set {
            objc_setAssociatedObject(self,
                                     &AssociatedKey.startPos,
                                     newValue,
                                     .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    // 请求条目
    var reqCount: Int {
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.reqCount) as? Int ?? 20
        }
        set {
            objc_setAssociatedObject(self,
                                     &AssociatedKey.reqCount,
                                     newValue,
                                     .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    // 没有更多
    var noMore: Bool {
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.noMore) as? Bool ?? false
        }
        set {
            objc_setAssociatedObject(self,
                                     &AssociatedKey.noMore,
                                     newValue,
                                     .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    // 是否正在下拉刷新
    var headerRefreshing: Bool {
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.headerRefreshing) as? Bool ?? false
        }
        set {
            objc_setAssociatedObject(self,
                                     &AssociatedKey.headerRefreshing,
                                     newValue,
                                     .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    // 是否有上拉加载
    var hasFooter: Bool {
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.hasFooter) as? Bool ?? false
        }
        set {
            objc_setAssociatedObject(self,
                                     &AssociatedKey.hasFooter,
                                     newValue,
                                     .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    // 未加载
    var notLoaded: Bool {
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.notLoaded) as? Bool ?? true
        }
        set {
            objc_setAssociatedObject(self,
                                     &AssociatedKey.notLoaded,
                                     newValue,
                                     .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    /// 下拉刷新
    /// - Parameters:
    ///   - animation: 是否有动画
    ///   - blockMs: 回调数据
    public func addHeaderWithBeginRefresh(animate: Bool,
                                          blockStartPosAndCount: @escaping HeaderRefreshBlock) {
        weak var weakSelf = self
        weakSelf?.resetPageNum()
        let header = MJRefreshNormalHeader {
            weakSelf?.resetPageNum()
            weakSelf?.notLoaded = false
            blockStartPosAndCount(weakSelf?.startPos ?? 1, weakSelf?.reqCount ?? 20)
        }
        header.mj_h = 70
        header.lastUpdatedTimeLabel?.isHidden = true
        weakSelf?.mj_header = header
        if animate {
            // 有动画的刷新
            weakSelf?.mj_header?.beginRefreshing()
        } else {
            // 刷新，但是没有动画
            weakSelf?.mj_header?.executeRefreshingCallback()
        }
    }
    
    /// 上拉加载
    /// - Parameters:
    ///   - blockMs: 回调数据
    public func addFooterWithAutoRefresh(blockStartPosAndCount: @escaping HeaderRefreshBlock) {
        weak var weakSelf = self
        guard weakSelf?.hasFooter == true else { Log_y.print_("无更多数据，故而没有上拉加载") ;return }
        let footer = MJRefreshBackNormalFooter {
            if weakSelf?.noMore == true {
                blockStartPosAndCount(weakSelf?.startPos ?? 1, weakSelf?.reqCount ?? 20)
            } else {
                weakSelf?.startPos += (weakSelf?.reqCount ?? 20)
                blockStartPosAndCount(weakSelf?.startPos ?? 1, weakSelf?.reqCount ?? 20)
            }
        }
        let s = DispatchTimeInterval.milliseconds(200)
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + s) {
            weakSelf?.mj_footer = footer
        }
    }
    
    /// 处理数据源
    /// - Parameters:
    ///   - isRef: 下拉刷新
    ///   - mutArr: 数据源
    public func handleData<M: Mappable>(isRef: Bool, sourceArr: inout [M], newArr: [M]) {
        weak var weakSelf = self
        weakSelf?.catchErrMsg = ""
        if isRef {
            weakSelf?.hasFooter = !newArr.isEmpty
            weakSelf?.headerRefreshing = false
            sourceArr = newArr
        } else {
            for i in 0..<newArr.count {
                sourceArr.append(newArr[i])
            }
        }
    }
    
    /// 结束刷新
    public func endRefreshing() {
        weak var weakSelf = self
        weakSelf?.headerRefreshing = false
        mj_header?.endRefreshing()
        mj_footer?.endRefreshing()
    }
    
    // 重置起始位置
    fileprivate func resetPageNum() {
        weak var weakSelf = self
        weakSelf?.headerRefreshing = true
        weakSelf?.startPos = 1
        weakSelf?.noMore = false
    }
}



